﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SP = Microsoft.SharePoint.Client;
using System.DirectoryServices.AccountManagement;

namespace com.sharepointutils.application.Forms
{
    public partial class SecurityForm : Form
    {
        const String DOMAIN = "nsight";


        public SecurityForm(SharePointConnection connection)
        {
            InitializeComponent();
            if (connection != null)
            {
                this.Connection = connection;
                lbl_site.Text = Connection.Label;
                this.Tag = Connection.Label;
                this.Text = "Security - " + connection.URL;
            }
        }

        public SharePointConnection Connection { get; set; }
        String List { get; set; }

        private void button_getUsers_Click(object sender, EventArgs e)
        {
            List<UserSecurity> users = new List<UserSecurity>();
            using (SP.ClientContext context = new SP.ClientContext(Connection.URL))
            {
                context.Credentials = Connection.Credentials;
                SP.Web web = context.Web;
                
                context.Load(web.RoleAssignments);
                
                context.ExecuteQuery();
                foreach(SP.RoleAssignment ra in web.RoleAssignments)
                {
                    context.Load(ra.Member);
                    context.Load(ra.RoleDefinitionBindings);
                    context.ExecuteQuery();

                    switch(ra.Member.PrincipalType)
                    {
                        case SP.Utilities.PrincipalType.User:
                            users.Add(new UserSecurity(ra.Member.Title, ra.Member.LoginName, getRoles(ra.RoleDefinitionBindings)));
                            break;
                        case SP.Utilities.PrincipalType.SharePointGroup:
                            users.AddRange(getUsersInGroup(context, ra.Member.Id, getRoles(ra.RoleDefinitionBindings) , ra.Member.LoginName));                            
                            break;
                        case SP.Utilities.PrincipalType.DistributionList:
                        case SP.Utilities.PrincipalType.SecurityGroup:
                            users.AddRange(getUsersInADGroup(ra.Member.LoginName, DOMAIN, getRoles(ra.RoleDefinitionBindings)));
                            break;
                    }
                }
                gv_results.DataSource = users;
                lbl_count.Text = "Count: " + users.Count;
            }
        }

        private String getRoles(SP.RoleDefinitionBindingCollection collection )
        {
            StringBuilder roles = new StringBuilder();

            foreach(SP.RoleDefinition def in collection)
            {
                roles.Append(def.Name+ ";");
            }
            return roles.ToString();
        }

        private List<UserSecurity> getUsersInADGroup (String groupName, String domain, String roles, String parentGroup = null)
        {
            List<UserSecurity> users = new List<UserSecurity>();
            PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domain);
            GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, groupName);

            if (grp != null)
            {
                foreach (Principal p in grp.GetMembers(false))
                {
                    users.Add(new UserSecurity(p.DisplayName, domain + "\\" + p.SamAccountName, roles, parentGroup));
                }
                grp.Dispose();
                ctx.Dispose();
            }

            return users;
        }

        private List<GroupSecurity> getGroupsbyUser(String username, String domain)
        {
            List<GroupSecurity> groups = new List<GroupSecurity>();

            using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domain))
            {
                using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username))
                {
                    if (user != null)
                    {
                        foreach (Principal p in user.GetGroups())
                        {
                            groups.Add(new GroupSecurity(p));
                        }
                    }
                }
            }
            return groups;
        }

        private List<UserSecurity> getUsersInGroup (SP.ClientContext context, int id, String roles, String groupName)
        {
            List<UserSecurity> users = new List<UserSecurity>();

            SP.GroupCollection groupCollection = context.Web.SiteGroups;
            SP.Group oGroup = groupCollection.GetById(id);
            SP.UserCollection collUser = oGroup.Users;
            context.Load(collUser);
            context.ExecuteQuery();

            foreach (SP.User oUser in collUser)
            {
                switch(oUser.PrincipalType)
                {
                    case SP.Utilities.PrincipalType.User:
                        users.Add(new UserSecurity(oUser.Title, oUser.LoginName, roles, groupName));
                        break;
                    case SP.Utilities.PrincipalType.SecurityGroup:
                    case SP.Utilities.PrincipalType.DistributionList:
                        users.AddRange(getUsersInADGroup(oUser.LoginName, DOMAIN, roles));
                        break;
                }
                
            }
            return users;
        }

        private void btn_getUsersInADGroup_Click(object sender, EventArgs e)
        {
            List<UserSecurity> users = getUsersInADGroup(txt_adGroup.Text, DOMAIN, "");
            gv_results.DataSource = users;
            lbl_count.Text = "Count: " + users.Count;
        }

        private void btn_getGroupsUser_Click(object sender, EventArgs e)
        {
            List<GroupSecurity> groups = getGroupsbyUser(txt_adGroup.Text, DOMAIN);
            gv_results.DataSource = groups;
            lbl_count.Text = "Count: " + groups.Count;
        }


    }

    public class UserSecurity
    {
        public String Name { get; set; }
        public String Login { get; set; }
        public String Access { get; set; }
        public String Group { get; set; }

        public UserSecurity(String name, String login, String access)
        {
            this.Name = name;
            this.Login = login;
            this.Access = access;
        }

        public UserSecurity(String name, String login, String access, String group)
        {
            this.Name = name;
            this.Login = login;
            this.Access = access;
            this.Group = group;
        }
    }

    public class GroupSecurity
    {
        public String Description { get; set; }
        public String SamAccountName { get; set; }

        public GroupSecurity(Principal p)
        {
            this.Description = p.Description;
            this.SamAccountName = p.SamAccountName;
        }

    }
}
